package com.xc.sys.service;

import com.xc.common.object.PageInfo;
import com.xc.common.tool.BeanAid;
import com.xc.common.tool.Helper;
import com.xc.db.Tables;
import com.xc.db.tables.SysOrganization;
import com.xc.db.tables.SysUser;
import com.xc.db.tables.records.SysUserRecord;
import com.xc.sys.entity.SysOrganizationEntity;
import com.xc.sys.entity.SysUserEntity;
import com.xc.sys.vo.SysUserVO;
import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.StringUtils;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Result;
import org.jooq.SelectConditionStep;
import org.jooq.SelectField;
import org.jooq.SelectForUpdateStep;
import org.jooq.SelectSeekStepN;
import org.jooq.SortField;
import org.jooq.impl.DSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SysUserService {
	@Autowired
	private DSLContext dsl;
	@Autowired
	private SysOrganizationService sysOrganizationService;
	private SysUser USER = SysUser.SYS_USER.as("USER");
	private SysOrganization ORG = SysOrganization.SYS_ORGANIZATION.as("ORG");
	public Record getById(String id) {
		Record record = this.dsl.select(new SelectField[0]).from(this.USER)
				.where(new Condition[] { this.USER.ID.eq(Integer.valueOf(id)) }).fetchOne();
		return record;
	}
	public Record getById(Integer id) {
		Record record = this.dsl.select(new SelectField[0]).from(this.USER)
				.where(new Condition[] { USER.ID.eq(id) }).fetchOne();
		return record;
	}

	public SysUserEntity getEntityById(Integer id) {
		Record record = this.dsl.select(new SelectField[0]).from(this.USER)
				.where(new Condition[] { this.USER.ID.eq(id) }).fetchOne();
		SysUserEntity user = null;
		if (record != null) {
			user = (SysUserEntity) record.into(SysUserEntity.class);
		}
		return user;
	}
	public SysUserEntity getEntityById(String id) {
		Record record = this.dsl.select(new SelectField[0]).from(this.USER)
				.where(new Condition[] { this.USER.ID.eq(Integer.valueOf(id)) }).fetchOne();
		SysUserEntity user = null;
		if (record != null) {
			user = (SysUserEntity) record.into(SysUserEntity.class);
		}
		return user;
	}
	public SysUserVO getVoById(Integer id) {
		Record record = this.dsl.select().from(USER)
				.where(new Condition[] { USER.ID.eq(id) }).fetchOne();
		SysUserVO user = null;
		if (record != null) {
			user = record.into(SysUserVO.class);
		}
		return user;
	}
	public SysUserVO getVoById(String id) {
		Record record = this.dsl.select().from(USER)
				.where(new Condition[] { this.USER.ID.eq(Integer.valueOf(id)) }).fetchOne();
		SysUserVO user = null;
		if (record != null) {
			user = record.into(SysUserVO.class);
		}
		return user;
	}

	public Result<Record> select(Condition whr, PageInfo<SysUserEntity> pageInfo,SortField<?>... orderby) {
		SelectSeekStepN<Record> seek = dsl.select().from(USER).where(whr).orderBy(orderby);
		Result<Record> result = null;
		if (pageInfo != null) {
			SelectForUpdateStep<Record> su = seek.limit(pageInfo.getLimit()).offset(pageInfo.getBeginNum());
			result = su.fetch();
		} else {
			result = seek.fetch();
		}
		if (pageInfo != null) {
			pageInfo.setResult(result);
		}
		List<SysUserEntity> list = result.into(SysUserEntity.class);
		pageInfo.setResult(result);
		pageInfo.setList(list);
		return result;
	}

	public List<SysUserEntity> select(Condition whr, SortField<?>... orderby) {
		Result<Record> result = null;
		if (orderby == null) {
			SelectConditionStep<Record> su = dsl.select(new SelectField[0]).from(this.USER).where(whr);
			result = su.fetch();
		} else {
			SelectSeekStepN<Record> su = dsl.select(new SelectField[0]).from(this.USER).where(whr).orderBy(orderby);
			result = su.fetch();
		}
		List<SysUserEntity> list = result.into(SysUserEntity.class);
		return list;
	}
	public List<SysUserVO> selectVo(Condition whr, SortField<?>... orderby) {
		Result<Record> result = null;
		if (orderby == null) {
			result = this.dsl.select(new SelectField[0]).from(this.USER).where(whr).fetch();
		} else {
			result = this.dsl.select(new SelectField[0]).from(this.USER).where(whr).orderBy(orderby).fetch();
		}
		List<SysUserVO> list = result.into(SysUserVO.class);
		return list;
	}

	public Long count(Condition cond) {
		Long count = null;
		SelectConditionStep<Record1<Integer>> su = dsl.selectCount().from(USER).where(new Condition[] { cond });
		count = (Long) su.fetchOneInto(Long.class);
		return count;
	}

	public void update(SysUserEntity entity) {
		SysUserRecord record = new SysUserRecord();
		SysUserEntity entity2 = getEntityById(entity.getId());
		if(!entity2.getName().equals(entity.getName())) {
			String[] names = Helper.getPinyin(entity.getName());
			entity.setInitialLetter(StringUtils.join(names[0],""));
			entity.setFullPinyin(StringUtils.join(names[1],""));
		}
		record.from(entity);
		this.dsl.executeUpdate(record);
		invalidateCache(entity.getId());
	}
	public void updateVo(SysUserVO vo) {
		SysUserRecord record = new SysUserRecord();
		record.from(vo);
		this.dsl.executeUpdate(record);
		invalidateCache(vo.getId());
	}
	public Integer insert(SysUserEntity entity) {
		SysUserRecord record = new SysUserRecord();
		String[] names = Helper.getPinyin(entity.getName());
		entity.setInitialLetter(StringUtils.join(names[0],""));
		entity.setFullPinyin(StringUtils.join(names[1],""));
		record.from(entity);
		Integer id = dsl.insertInto(Tables.SYS_USER).set(record).returning(USER.ID).fetchOne().getId();
		invalidateCache(id);
		return id;
	}
	@Transactional
	public String insert(List<SysUserEntity> list) {
		List<SysUserRecord> records = Lists.newArrayList();
		for(SysUserEntity entity : list) {
			SysUserRecord record = new SysUserRecord();
			record.from(entity);
			records.add(record);
		}
		this.dsl.batchInsert(records).execute();
		return null;
	}
	public void deleteById(String id) {
		deleteById(Integer.valueOf(id));
	}
	public void deleteById(Integer id) {
		dsl.delete(USER).where(new Condition[] { USER.ID.eq(id) }).execute();
		invalidateCache(id);
	}
	@Transactional
	public void deleteAll() {
		
		dsl.delete(USER).where(USER.ID.notEqual(1)).execute();
	}

	public static LoadingCache<Integer, Optional<SysUserVO>> userCache = CacheBuilder.newBuilder().maximumSize(5000)
			.build(new CacheLoader<Integer, Optional<SysUserVO>>() {
				public Optional<SysUserVO> load(Integer id) {
					SysUserService userService = BeanAid.getBean(SysUserService.class);
					SysUserVO user = userService.getVoById(id);
					return Optional.fromNullable(user);
				}
			});

	public static SysUserVO getFrameCaches(Integer id) {
		if (id == null) {
			return null;
		}
		try {
			return userCache.get(id).orNull();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static SysUserVO getFrameCaches(String id) {
		if (id == null||id.equals("")) {
			return null;
		}
		try {
			return userCache.get(Integer.valueOf(id)).orNull();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static LoadingCache<String, Optional<SysUserVO>> idNumberCache = CacheBuilder.newBuilder().maximumSize(5000)
			.build(new CacheLoader<String, Optional<SysUserVO>>() {
				public Optional<SysUserVO> load(String idNumber) {
					SysUserService userService = BeanAid.getBean(SysUserService.class);
					List<SysUserVO> users = userService.selectVo(DSL.field("ID_NUMBER").eq(idNumber));
					SysUserVO user = null;
					if(users.size()==1) {
						user = users.get(0);
					}
					return Optional.fromNullable(user);
				}
			});
	
	public static SysUserVO getFrameIdNumberCaches(String id) {
		if (id == null) {
			return null;
		}
		try {
			return idNumberCache.get(id).orNull();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}
	public void invalidateCache(String id) {
		userCache.invalidate(Integer.valueOf(id));
	}
	public void invalidateCache(Integer id) {
		userCache.invalidate(id);
	}
}
